package com.norbitltd.guavaleaves.java.math;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.MathContext;
import java.math.RoundingMode;

import com.google.common.base.Function;

public class BigDecimalFunctions {
	// TODO Not yet implemented!

	public static Function<BigDecimal, BigDecimal> abs() {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.abs();
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> abs(final MathContext context) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.abs(context);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> add(final BigDecimal augend) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.add(augend);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> add(final BigDecimal augend,
			final MathContext context) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.add(augend, context);
			}
		};
	}

	public static Function<BigDecimal, Byte> byteValueExact() {
		return new Function<BigDecimal, Byte>() {
			public Byte apply(BigDecimal input) {
				return input.byteValueExact();
			}
		};
	}

	// TODO isGreater, lower, etc

	public static Function<BigDecimal, BigDecimal> divide(
			final BigDecimal divisor) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.divide(divisor);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> divide(
			final BigDecimal divisor, final int roundingMode) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.divide(divisor, roundingMode);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> divide(
			final BigDecimal divisor, final int scale, final int roundingMode) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.divide(divisor, scale, roundingMode);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> divide(
			final BigDecimal divisor, final int scale,
			final RoundingMode roundingMode) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.divide(divisor, scale, roundingMode);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> divide(
			final BigDecimal divisor, final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.divide(divisor, mathContext);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> divide(
			final BigDecimal divisor, final RoundingMode roundingMode) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.divide(divisor, roundingMode);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal[]> divideAndRemainder(
			final BigDecimal divisor) {
		return new Function<BigDecimal, BigDecimal[]>() {
			public BigDecimal[] apply(BigDecimal input) {
				return input.divideAndRemainder(divisor);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal[]> divideAndRemainder(
			final BigDecimal divisor, final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal[]>() {
			public BigDecimal[] apply(BigDecimal input) {
				return input.divideAndRemainder(divisor, mathContext);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> divideToIntegralValue(
			final BigDecimal divisor) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.divideToIntegralValue(divisor);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> divideToIntegralValue(
			final BigDecimal divisor, final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.divideToIntegralValue(divisor, mathContext);
			}
		};
	}

	public static Function<BigDecimal, Double> doubleValue() {
		return new Function<BigDecimal, Double>() {
			public Double apply(BigDecimal input) {
				return input.doubleValue();
			}
		};
	}
	
	public static Function<BigDecimal, Float> floatValue() {
		return new Function<BigDecimal, Float>() {
			public Float apply(BigDecimal input) {
				return input.floatValue();
			}
		};
	}
	
	public static Function<BigDecimal, Integer> intValue() {
		return new Function<BigDecimal, Integer>() {
			public Integer apply(BigDecimal input) {
				return input.intValue();
			}
		};
	}
	
	public static Function<BigDecimal, Integer> intValueExact() {
		return new Function<BigDecimal, Integer>() {
			public Integer apply(BigDecimal input) {
				return input.intValueExact();
			}
		};
	}
	
	public static Function<BigDecimal, Long> longValue() {
		return new Function<BigDecimal, Long>() {
			public Long apply(BigDecimal input) {
				return input.longValue();
			}
		};
	}
	
	public static Function<BigDecimal, Long> longValueExact() {
		return new Function<BigDecimal, Long>() {
			public Long apply(BigDecimal input) {
				return input.longValueExact();
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> max(final BigDecimal val) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.max(val);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> min(final BigDecimal val) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.min(val);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> movePointLeft(final int n) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.movePointLeft(n);
			}
		};
	}

	public static Function<BigDecimal, BigDecimal> movePointRight(final int n) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.movePointRight(n);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> multiply(
			final BigDecimal multiplicand) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.multiply(multiplicand);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> multiply(
			final BigDecimal multiplicand, final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.multiply(multiplicand, mathContext);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> negate() {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.negate();
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> negate(
			final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.negate(mathContext);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> plus() {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.plus();
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> plus(
			final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.plus(mathContext);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> pow(
			final int n) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.pow(n);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> pow(
			final int n, final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.pow(n, mathContext);
			}
		};
	}
	
	public static Function<BigDecimal, Integer> precision() {
		return new Function<BigDecimal, Integer>() {
			public Integer apply(BigDecimal input) {
				return input.precision();
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> remainder(
			final BigDecimal divisor) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.remainder(divisor);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> remainder(
			final BigDecimal divisor, final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.remainder(divisor, mathContext);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> round(
			final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.round(mathContext);
			}
		};
	}
	
	public static Function<BigDecimal, Integer> scale() {
		return new Function<BigDecimal, Integer>() {
			public Integer apply(BigDecimal input) {
				return input.scale();
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> scaleByPowerOfTen(
			final int n) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.scaleByPowerOfTen(n);
			}
		};
	}
	
	
	public static Function<BigDecimal, BigDecimal> setScale(
			final int newScale) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.setScale(newScale);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> setScale(
			final int newScale, final int roundingMode) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.setScale(newScale, roundingMode);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> setScale(
			final int newScale, final RoundingMode roundingMode) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.setScale(newScale, roundingMode);
			}
		};
	}
	
	public static Function<BigDecimal, Short> shortValueExact() {
		return new Function<BigDecimal, Short>() {
			public Short apply(BigDecimal input) {
				return input.shortValueExact();
			}
		};
	}
	
	public static Function<BigDecimal, Integer> signum() {
		return new Function<BigDecimal, Integer>() {
			public Integer apply(BigDecimal input) {
				return input.signum();
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> stripTrailingZeros() {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.stripTrailingZeros();
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> subtract(
			final BigDecimal subtrahend) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.subtract(subtrahend);
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> subtract(
			final BigDecimal subtrahend, final MathContext mathContext) {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.subtract(subtrahend, mathContext);
			}
		};
	}
	
	public static Function<BigDecimal, BigInteger> toBigInteger() {
		return new Function<BigDecimal, BigInteger>() {
			public BigInteger apply(BigDecimal input) {
				return input.toBigInteger();
			}
		};
	}
	
	public static Function<BigDecimal, BigInteger> toBigIntegerExact() {
		return new Function<BigDecimal, BigInteger>() {
			public BigInteger apply(BigDecimal input) {
				return input.toBigIntegerExact();
			}
		};
	}
	
	public static Function<BigDecimal, String> toEngineeringString() {
		return new Function<BigDecimal, String>() {
			public String apply(BigDecimal input) {
				return input.toEngineeringString();
			}
		};
	}
	
	public static Function<BigDecimal, String> toPlainString() {
		return new Function<BigDecimal, String>() {
			public String apply(BigDecimal input) {
				return input.toPlainString();
			}
		};
	}
	
	public static Function<BigDecimal, BigDecimal> ulp() {
		return new Function<BigDecimal, BigDecimal>() {
			public BigDecimal apply(BigDecimal input) {
				return input.ulp();
			}
		};
	}
	
	public static Function<BigDecimal, BigInteger> unscaledValue() {
		return new Function<BigDecimal, BigInteger>() {
			public BigInteger apply(BigDecimal input) {
				return input.unscaledValue();
			}
		};
	}
}
